package com.glela.sensitiveWords.util;

import com.glela.sensitiveWords.beans.SensitiveWordsFilterResult;
import com.glela.sensitiveWords.beans.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by liujie 
 */
public class SensitiveWordsFilterUtils {
    private static Logger logger = LoggerFactory.getLogger(SensitiveWordsFilterUtils.class);

    public static Node tree = new Node();

    private static void insertWord(String word) {
        Node node = tree;
        for (int i = 0; i < word.length(); ++i) {
            node = node.addChar(word.charAt(i));
        }
        node.setIsEnd(true);
    }

    /**
     * 判断是否是特殊符号
     *
     * @param c
     * @return
     */
    private static boolean isPunctuationChar(String c) {
        String regex = "[\\pP\\pZ\\pS\\pM\\pC]";
        Pattern p = Pattern.compile(regex, 2);
        Matcher m = p.matcher(c);
        return m.find();
    }

    private static PunctuationOrHtmlFilteredResult filterPunctation(String originalString) {
        StringBuffer filteredString = new StringBuffer();
        ArrayList<Integer> charOffsets = new ArrayList<Integer>();

        for (int result = 0; result < originalString.length(); ++result) {
            String c = String.valueOf(originalString.charAt(result));
            if (!isPunctuationChar(c)) {
                filteredString.append(c);
                charOffsets.add(Integer.valueOf(result));
            }
        }

        PunctuationOrHtmlFilteredResult filteredResult = new PunctuationOrHtmlFilteredResult();
        filteredResult.setOriginalString(originalString);
        filteredResult.setFilteredString(filteredString);
        filteredResult.setCharOffsets(charOffsets);
        return filteredResult;
    }

    private static PunctuationOrHtmlFilteredResult filterPunctationAndHtml(String originalString) {
        StringBuffer filteredString = new StringBuffer();
        ArrayList<Integer> charOffsets = new ArrayList<Integer>();
        int result = 0;

        for (; result < originalString.length(); ++result) {
            String c = String.valueOf(originalString.charAt(result));
            if (originalString.charAt(result) != 60) {
                if (!isPunctuationChar(c)) {
                    filteredString.append(c);
                    charOffsets.add(Integer.valueOf(result));
                }
            } else {
                int last;
                for (last = result + 1; last < originalString.length(); ++last) {
                    if (originalString.charAt(last) == 60) {
                        last = result;
                        break;
                    }

                    if (originalString.charAt(last) == 62) {
                        break;
                    }
                }

                result = last;
            }
        }

        PunctuationOrHtmlFilteredResult filteredResult = new PunctuationOrHtmlFilteredResult();
        filteredResult.setOriginalString(originalString);
        filteredResult.setFilteredString(filteredString);
        filteredResult.setCharOffsets(charOffsets);
        return filteredResult;
    }

    private static SensitiveWordsFilterResult filter(PunctuationOrHtmlFilteredResult pohResult, char replacement) {
        StringBuffer sentence = pohResult.getFilteredString();
        ArrayList<Integer> charOffsets = pohResult.getCharOffsets();
        StringBuffer resultString = new StringBuffer(pohResult.getOriginalString());
        StringBuffer badWords = new StringBuffer();
//        int level = 0;
        Node node = tree;
//        boolean start = false;
//        boolean end = false;

        for (int result = 0; result < sentence.length(); ++result) {
            int last = result;
            node = tree;

            int k;
            for (k = result; k < sentence.length(); ++k) {
                node = node.findChar(sentence.charAt(k));
                if (node == null) {
                    break;
                }
                if (node.getIsEnd()) {
                    last = k;
                }
            }

            if (last > result) {
                for (k = result; k <= last; ++k) {
                    resultString.setCharAt(((Integer) charOffsets.get(k)).intValue(), replacement);
                }

                if (badWords.length() > 0) {
                    badWords.append(",");
                }

                badWords.append(sentence.substring(result, last + 1));
                result = last;
            }
        }

        SensitiveWordsFilterResult filterResult = new SensitiveWordsFilterResult();
        filterResult.setOriginalContent(pohResult.getOriginalString());
        filterResult.setFilteredContent(resultString.toString());
        filterResult.setBadWords(badWords.toString());
        return filterResult;
    }

    public static SensitiveWordsFilterResult filterText(String originalString, char replacement) {
        return filter(filterPunctation(originalString), replacement);
    }

    public static Node parseFile(String filePath) throws Exception {
        tree = new Node();
        InputStream is = null;
        try {
            is = new FileInputStream(new File(filePath));
            InputStreamReader e = new InputStreamReader(is, "UTF-8");
            Properties prop = new Properties();
            prop.load(e);
            Enumeration<?> en = prop.propertyNames();
            while (en.hasMoreElements()) {
                String word = (String) en.nextElement();
                insertWord(word);
            }
            return tree;
        } catch (UnsupportedEncodingException e) {
            logger.error("敏感词文件编码错误", e);
            throw new Exception("敏感词文件编码错误");
        } catch (IOException e1) {
            logger.error("敏感词文件读取错误", e1);
            throw new Exception("敏感词文件读取错误");
        } catch (Exception e3) {
            logger.error("敏感词文件处理错误", e3);
            throw new Exception("敏感词文件处理错误");
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e2) {
                    logger.error("敏感词文件关闭错误", e2);
                    throw new Exception("敏感词文件关闭错误");
                }
            }
        }
    }

    private static class PunctuationOrHtmlFilteredResult {
        private String originalString;
        private StringBuffer filteredString;
        private ArrayList<Integer> charOffsets;

        private PunctuationOrHtmlFilteredResult() {
        }

        public String getOriginalString() {
            return this.originalString;
        }

        public void setOriginalString(String originalString) {
            this.originalString = originalString;
        }

        public StringBuffer getFilteredString() {
            return this.filteredString;
        }

        public void setFilteredString(StringBuffer filteredString) {
            this.filteredString = filteredString;
        }

        public ArrayList<Integer> getCharOffsets() {
            return this.charOffsets;
        }

        public void setCharOffsets(ArrayList<Integer> charOffsets) {
            this.charOffsets = charOffsets;
        }
    }
}
